package com.hibase.core.web.aspect;


import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.hibase.common.constant.RedisKeyConstant;
import com.hibase.common.constant.ResponseCode;
import com.hibase.common.entity.ResponseModel;
import com.hibase.common.entity.User;
import com.hibase.common.util.UserContext;
import com.hibase.core.redis.util.RedisUtil;
import com.hibase.core.web.annotation.HibaseRepeatIntercept;
import com.hibase.core.web.utils.ShaUtils;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * 防重复提交切面
 *
 * @author li-wei-hua
 */
@Slf4j
@Aspect
@Order(10)
@Component
public class NoRepeatSubmitAspect {

    @Autowired
    private RedisUtil redisUtil;

    @Pointcut("@annotation(com.hibase.core.web.annotation.HibaseRepeatIntercept)")
    public void pointCut() {
    }


    @Around("pointCut()")
    public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
        log.debug("[防重复提交验证开始]");
        Object result = null;
        //获取request
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        HttpServletRequest request = servletRequestAttributes.getRequest();
        // 获取出方法上的注解
        Method method = ((MethodSignature) pjp.getSignature()).getMethod();
        HibaseRepeatIntercept submit = method.getAnnotation(HibaseRepeatIntercept.class);
        User user = UserContext.get();
        String key = getKey(request.getServletPath(), Lists.newArrayList(pjp.getArgs()).toString(), user.getLoginName());
        //如果缓存中有这个用户访问url视为重复提交
        if (!redisUtil.hasKey(key)) {
            redisUtil.setEx(key,Boolean.TRUE,submit.value(), TimeUnit.MILLISECONDS);
            result = pjp.proceed();
            redisUtil.delete(key);
        } else {
            log.error("[防重复提交验证]: {}访问{}重复提交", user.getLoginName(), request.getServletPath());
            return ResponseModel.failMsg(ResponseCode.SERVER_ERROR.getCode(), "点击的太快了,请慢一点!");
        }
        log.debug("[防重复提交验证结束]");
        return result;
    }

    /**
     * key规则  前缀+用户名+url
     *
     * @param url
     * @return
     */
    private String getKey(String url, String body, String username) {
        StringBuilder encryption = new StringBuilder();
        encryption.append(username)
                .append(StrUtil.COLON)
                .append(url)
                .append(StrUtil.COLON)
                .append(body);
        return new StringBuilder()
                .append(RedisKeyConstant.NO_REPEAT_SUBMIT)
                .append(StrUtil.COLON)
                .append(username)
                .append(StrUtil.COLON)
                .append(url)
                .append(StrUtil.COLON)
                .append(ShaUtils.shaDigest(encryption.toString(), username))
                .toString();
    }

    /**
     * key规则  前缀+用户名+url
     *
     * @param url
     * @return
     */
    private String getKey(String url, String username) {
        StringBuilder encryption = new StringBuilder();
        encryption.append(username)
                .append(StrUtil.COLON)
                .append(url);
        return new StringBuilder()
                .append(RedisKeyConstant.NO_REPEAT_SUBMIT)
                .append(StrUtil.COLON)
                .append(username)
                .append(StrUtil.COLON)
                .append(url)
                .append(StrUtil.COLON)
                .append(ShaUtils.shaDigest(encryption.toString(), username))
                .toString();

    }
}
